﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Vowei.Core.Models;
using System.Diagnostics;

namespace Vowei.Core.Scm
{
    public class ScmLogFormatter
    { 
        protected enum Command
        { 
            Changed,
            Deleted,
            Added,
            PropertyChanged,
            FileChanged,
            Renamed
        }

        protected static Dictionary<Command, string> _cssStyles;
        static ScmLogFormatter()
        {
            _cssStyles = new Dictionary<Command, string>();
            _cssStyles.Add(Command.Changed, "scm_changed");
            _cssStyles.Add(Command.Deleted, "scm_deleted");
            _cssStyles.Add(Command.Added, "scm_added");
            _cssStyles.Add(Command.PropertyChanged, "scm_property_changed");
            _cssStyles.Add(Command.FileChanged, "scm_file_changed");
            _cssStyles.Add(Command.Renamed, "scm_renamed");
        }
    }

    public class SvnLogFormatter : ScmLogFormatter
    {
        public string[] FormatChangedLog(string clText, Project project)
        {
            if (project == null)
                throw new ArgumentNullException("project");

            if (string.IsNullOrEmpty(clText))
                return null;

            var results = new List<string>();
            int pathBeginIdx = 0;
            int pathEndIdx = 0;
            int i = 0;
            while (i < clText.Length)
            {
                var c = clText[i];
                var currentCmd = Command.FileChanged;

                switch (c)
                {
                    case '_':
                        if (i + 1 >= clText.Length)
                            throw new InvalidOperationException("错误的输入Svn日志，在新的一行，字符‘_’后面应该是'U'");
                        if (clText[i + 1] != 'U')
                            throw new InvalidOperationException("错误的输入Svn日志，在新的一行，字符‘_’后面应该是'U'");

                        currentCmd = Command.PropertyChanged;
                        i++;
                        break;

                    case 'D':
                        currentCmd = Command.Deleted;
                        break;

                    case 'A':
                        var j = i + 1;
                        while (j < clText.Length && char.IsWhiteSpace(clText[j]))
                            j++;
                        if (clText[j] == '+')
                        {
                            currentCmd = Command.Renamed;
                            i = j;
                        }
                        else
                            currentCmd = Command.Added;

                        break;

                    case 'U':
                        if (i < (clText.Length - 1) && clText[i + 1] == 'U')
                        {
                            currentCmd = Command.Changed;
                            i++;
                        }
                        else
                            currentCmd = Command.FileChanged;

                        break;

                    default:
                        throw new InvalidOperationException(string.Format("无法识别的Svn命令： {0}", c));
                }

                i++;

                // 跳过空格
                while (i < clText.Length && char.IsWhiteSpace(clText[i]))
                    i++;

                pathBeginIdx = i;
                while (i < clText.Length && clText[i] != '\n')
                    i++;
                pathEndIdx = i - 1;

                var path = clText.Substring(pathBeginIdx, pathEndIdx - pathBeginIdx + 1);
                var resultText = FormatFilePathInLog(path, currentCmd, project);

                while (i < clText.Length && (clText[i] == '\n' || clText[i] == '\r'))
                    i++;

                if (currentCmd == Command.Renamed)
                {
                    var lineBeginIdx = i;
                    while (i < clText.Length && char.IsWhiteSpace(clText[i]))
                        i++;

                    var renameSig = "(from";
                    if (string.CompareOrdinal(renameSig, 0, clText, i, renameSig.Length) == 0)
                    {
                        i += renameSig.Length + 1;
                        // 跳过"(from"后面的空格
                        while (i < clText.Length && char.IsWhiteSpace(clText[i]))
                            i++;

                        pathBeginIdx = i;
                        // 找到冒号:
                        while (i < clText.Length && clText[i] != ':')
                            i++;

                        pathEndIdx = i - 1;
                        var htmlText = FormatFilePathInLog(clText.Substring(pathBeginIdx, pathEndIdx - pathBeginIdx + 1),
                                                           Command.Deleted,
                                                           project);

                        //找到最后的换行符
                        while (i < clText.Length && clText[i] != '\n')
                            i++;
                        var lineEndIdx = i - 1;

                        resultText = string.Format("{0}<br />{1}{2}{3}<br />",
                                                   resultText,
                                                   clText.Substring(lineBeginIdx, pathBeginIdx - lineBeginIdx),
                                                   htmlText,
                                                   clText.Substring(pathEndIdx + 1, lineEndIdx - pathEndIdx));

                        while (i < clText.Length && (clText[i] == '\n' || clText[i] == '\r'))
                            i++;
                    }
                }
                results.Add(resultText);
            }

            return results.ToArray();
        }

        private string FormatFilePathInLog(string path, Command currentCmd, Project project)
        {
            Debug.Assert(!string.IsNullOrEmpty(path));
            if (string.IsNullOrEmpty(project.ScmUrl))
                throw new ArgumentNullException(string.Format("指定的项目 {0} 没有设定源代码版本控制程序的Web访问路径！", project.Title));

            var cssStyle = _cssStyles[currentCmd];
            var scmUrl = project.ScmUrl;
            if ( scmUrl[scmUrl.Length - 1] != '/' )
                return string.Format("<a class=\"{0}\" href=\"{1}/{2}\">{2}</a>", cssStyle, scmUrl, path);
            else
                return string.Format("<a class=\"{0}\" href=\"{1}{2}\">{2}</a>", cssStyle, scmUrl, path);
        }
    }
}